package com.zk.config.web.util;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.commons.collections.CollectionUtils;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.KeeperException.NoAuthException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.zk.config.api.util.ZkCom;
import com.zk.config.web.model.TreeData;
import com.zk.config.web.model.ZkCache;
import com.zk.config.web.op.Zk;

public class ZkCacheUtil {
	
	private static final Logger log = LoggerFactory.getLogger(ZkCacheUtil.class);
	
	public static TreeData setNodeCache(ZooKeeper zk, String checkPath) {
		TreeData td = ZkCache.zkData.get("/");
		if(td == null) {
			td = new TreeData();
			td.setText("");
			Map<String, String> state = new HashMap<>();
			state.put("opened", "true");
			td.setState(state);
			List<TreeData> ctdList = new ArrayList<>();
			td.setChildren(ctdList);
			if(ZkCache.useCache) {
				ZkCache.zkData.clear();
				ZkCache.zkData.put("/", td);
			}
			ComUtil.getChildren(zk, "/", ctdList, checkPath, ZkCache.useCache);
		}
		return td;
	}
	
	public static void createNodeSetCache(String path){
		if(ZkCache.useCache) {
			int index = path.lastIndexOf("/");
			String parent = ZkCom.getZkPath(path.substring(0, index));
			TreeData td = ZkCache.zkData.get(path);
			if (td == null) {
				TreeData treeData = new TreeData();
				treeData.setText(path.substring(index+1));
				TreeData ptd = ZkCache.zkData.get(parent);
				if(ptd == null) {
					createNodeSetCache(parent);
					ptd = ZkCache.zkData.get(parent);
				}
				List<TreeData> children = ptd.getChildren();
				if(children == null) {
					children = new ArrayList<>();
					ptd.setChildren(children);
				}
				children.add(treeData);
				ZkCache.zkData.put(path, treeData);
			} else {
				td.setData(null);
			}
		}
	}
	
	public static void childChangeSetCache(String path, List<String> children) {
		if(ZkCache.useCache && children != null) {
			TreeData ptd = ZkCache.zkData.get(path);
			if(ptd != null) {
				List<TreeData> tdList = ptd.getChildren();
				if(tdList != null) {
					tdList.clear();
					for(String c:children) {
						String cpath = !"/".equals(path)?(ZkCom.getZkPath(path)+"/"+c):ZkCom.getZkPath(c);
						TreeData td = new TreeData();
						td.setText(c);
						List<TreeData> ctdList = null;
						TreeData ctd = ZkCache.zkData.get(cpath);
						if(ctd != null) {
							ctdList = ctd.getChildren();
						}
						if(ctdList == null) {
							ctdList = new ArrayList<>();
						}
						if(ctdList.size() == 0) {
							td.setIcon("file");
						}
						td.setChildren(ctdList);
						ZkCache.zkData.put(cpath, td);
						tdList.add(td);
					}
				}
			}
		}
	}
	
	public static void changeNodeSetCache(String path){
		if(ZkCache.useCache) {
			TreeData treeData = ZkCache.zkData.get(path);
			if(treeData != null) {
				treeData.setData(null);
			}
		}
	}
	
	public static void getChildrenSetCache(ZooKeeper reader, String path, List<TreeData> tdList, boolean watch){
		if(ZkCache.useCache) {
			try {
				if(reader.exists(path, watch) != null) {
					List<String> children = reader.getChildren(path, watch);
					if (CollectionUtils.isNotEmpty(children)) {
						//Collections.sort(children);
					} else {
						return;
					}
					for(String c:children) {
						String cpath = !"/".equals(path)?(ZkCom.getZkPath(path)+"/"+c):ZkCom.getZkPath(c);
						TreeData ctd = ZkCache.zkData.get(cpath);
						if(ctd == null) {
							ctd = new TreeData();
							ctd.setText(c);
							List<TreeData> ctdList = new ArrayList<>();
							ctd.setChildren(ctdList);
							getChildrenSetCache(reader, cpath, ctdList, watch);
							if(ctdList.size() == 0) {
								ctd.setIcon("file");
							}
							ZkCache.zkData.put(cpath, ctd);
							tdList.add(ctd);
						}
					}
				}
			} catch (NoAuthException e) {
				log.warn(e.getMessage());
			} catch (Exception e) {
				e.printStackTrace();
				log.error(e.getMessage());
			}
		}
	}
	
	public static void deleteAllNodeClearCache(String path){
		if(ZkCache.useCache) {
			int index = path.lastIndexOf("/");
			String parent = ZkCom.getZkPath(path.substring(0, index));
			String name = path.substring(index+1);
			TreeData td = ZkCache.zkData.get(parent);
			if(td != null) {
				List<TreeData> children = td.getChildren();
				if(children != null) {
					int j = -1;
					for(int i = 0; i < children.size(); i++) {
						TreeData ctd = children.get(i);
						if(ctd == null) continue;
						if(name != null && name.equals(ctd.getText())) {
							j = i;
							if(ctd.getChildren() != null && ctd.getChildren().size() > 0) {
								ctd.getChildren().clear();
							}
							break;
						}
					}
					if(j > -1) {
						children.remove(j);
					}
				}
			}
			Iterator<Map.Entry<String, TreeData>> it = ZkCache.zkData.entrySet().iterator();
			while(it.hasNext()){
				Map.Entry<String, TreeData> entry = it.next();
				String key = entry.getKey();
				if(ZkCom.checkPath(path, key)) {
					it.remove();
				}
			}
		}
	}
	
	public static void deleteNodeClearCache(String path){
		if(ZkCache.useCache) {
			int index = path.lastIndexOf("/");
			String parent = ZkCom.getZkPath(path.substring(0, index));
			String name = path.substring(index+1);
			TreeData td = ZkCache.zkData.get(parent);
			if(td != null) {
				List<TreeData> children = td.getChildren();
				if(children != null) {
					int j = -1;
					for(int i = 0; i < children.size(); i++) {
						TreeData ctd = children.get(i);
						if(ctd == null) continue;
						if(name != null && name.equals(ctd.getText())) {
							j = i;
							break;
						}
					}
					if(j > -1) {
						children.remove(j);
					}
				}
			}
			if(ZkCache.zkData.containsKey(path)) {
				ZkCache.zkData.remove(path);
			}
		}
	}
	
	public static void setZkDataCache(List<TreeData> children, String path){
		if(children != null) {
			for(TreeData td:children) {
				String cpath = "/".equals(path)?(path + td.getText()):(path+"/" + td.getText());
				setZkDataCache(td.getChildren(), cpath);
				ZkCache.zkData.put(cpath, td);
			}
		}
	}
}
